using DA.AnimGraph;
using System.Collections.Generic;
using System.Reflection;
using UnityEditor.Experimental.GraphView;
using UnityEngine;
using UnityEngine.UIElements;

namespace DA.AnimGraph.Editor {
    internal abstract class NodeViewBase : Node {

        protected HandleKeeper<AGAHandle_Node> handleKeeper;
        private AnimGraphView graphView;
        private AGEEnvironment ageEnv;

        public AUID uuid { get; private set; }
        public abstract string titleText { get; }
        protected abstract NodeViewInspectorSourceBase dataSource { get; }

        public List<BlendTreePort> inputPorts { get; private set; }
        public BlendTreePort outputPort { get; private set; }

        protected ShowInspectorService showInspectorService => ageEnv.serviceManager.GetService<ShowInspectorService>();

        public Vector2 position {
            set {
                style.left = value.x;
                style.top = value.y;
            }
            get {
                return new Vector2(style.left.value.value, style.top.value.value);
            }
        }

        bool isMultiInputNode = false; // 现在的输入port只包括节点输入，不存在混合的情况，所以可以一起删

        internal virtual void Init(AGAHandle_Node handle, AnimGraphView graphView, AGEEnvironment ageEnv) {
            handleKeeper = handle.ToKeeper<AGAHandle_Node>();
            this.graphView = graphView;
            this.ageEnv = ageEnv;

            position = handle.position;
            uuid = handle.uuid;
            SetTitle();

            name = handle.uuid.ToDataString();

            // 样式手动修改
            VisualElement nodeBorder = this.Q("node-border");
            var uuidLabel = new Label($"# {uuid}") {
                style = {
                    fontSize = 8,
                }
            };
            nodeBorder.Insert(0, uuidLabel);
            titleButtonContainer.SetEnabled(false);
            titleButtonContainer.visible = false;

            //移动事件回调
            RegisterCallback<GeometryChangedEvent>(OnGeometryChanged);
            RegisterCallback<MouseDownEvent>(OnClick);

            inputPorts = new List<BlendTreePort>();
            SetPorts();
        }

        void SetTitle() {
            string text;
            if (dataSource != null && !string.IsNullOrEmpty(dataSource.nodeName.value)) {
                text = $"{titleText}\n( {dataSource.nodeName.value} )";
            } else {
                text = titleText;
            }
            title = text;
        }
        protected void SetTitleColor(StyleColor color) {
            VisualElement title = this.Q("node-border").Q("title");
            title.style.backgroundColor = color;
        }

        void SetPorts() {
            var handle = handleKeeper.handle;
            // 生成port
            FieldInfo[] fields = handle.data.GetType().GetFields();
            foreach (FieldInfo field in fields) {
                if (field.GetCustomAttribute<NodeInputPortAttribute>() != null) {
                    var name = field.GetCustomAttribute<NodeInputPortAttribute>().name;
                    var uuid = (AUID)field.GetValue(handle.data);
                    var port = CreatePort(uuid, Direction.Input);
                    port.name = name;
                    port.portName = name;
                    inputContainer.Add(port);
                    inputPorts.Add(port);
                } else if (field.GetCustomAttribute<NodeInputPortListAttribute>() != null) {
                    isMultiInputNode = true;
                    var groupName = field.GetCustomAttribute<NodeInputPortListAttribute>().groupName;
                    var inputInfoList = handle.GetAllInput();
                    //var inputChildren = field.GetValue(handle.data) as List<AUID>;
                    SetInputListPorts(groupName, inputInfoList);
                } else if (field.GetCustomAttribute<NodeOutputPortAttribute>() != null) {
                    var name = field.GetCustomAttribute<NodeOutputPortAttribute>().name;
                    var uuid = (AUID)field.GetValue(handle.data);
                    var port = CreatePort(uuid, Direction.Output);
                    port.name = name;
                    port.portName = name;
                    outputContainer.Add(port);
                    outputPort = port;
                }
            }
        }

        void SetInputListPorts(string groupName, List<(AUID, string)> inputChildren) {
            for (int i = 0; i < inputChildren.Count; i++) {
                var port = CreatePort(inputChildren[i].Item1, Direction.Input);
                port.name = $"[{i}] {inputChildren[i].Item2}";
                port.portName = port.name;
                inputContainer.Add(port);
                inputPorts.Add(port);
            }
        }
        void RebuildMuitiInputPorts() {
            for (int i = 0; i < inputPorts.Count; i++) {
                inputPorts[i].DisconnectAll();
            }
            inputPorts.Clear();
            inputContainer.Clear();

            var handle = handleKeeper.handle;
            FieldInfo[] fields = handle.data.GetType().GetFields();
            foreach (FieldInfo field in fields) {
                if (field.GetCustomAttribute<NodeInputPortListAttribute>() != null) {
                    var groupName = field.GetCustomAttribute<NodeInputPortListAttribute>().groupName;
                    var inputInfoList = handle.GetAllInput();
                    SetInputListPorts(groupName, inputInfoList);
                }
            }
        }

        protected BlendTreePort CreatePort(AUID uuid, Direction direction) {
            var port = new BlendTreePort(graphView, ageEnv, uuid, Orientation.Horizontal, direction, Port.Capacity.Single, null);
            return port;
        }

        // 节点位置变化事件
        private void OnGeometryChanged(GeometryChangedEvent evt) {
            handleKeeper.handle.position = evt.newRect.position;
        }
        private void OnClick(MouseDownEvent evt) {
            //Debug.Log($"{evt.clickCount}   {evt.button}");
            // 打开Inspector
            if (evt.clickCount == 1 && evt.button == 0) {
                var inspector = showInspectorService;
                if (!inspector.IsSourceEqual(dataSource)) {
                    inspector.ShowInspector(dataSource, OnInspectorChange, InspectorPane.ShowInspectorType.New);
                }
            }
        }

        public bool OnUpdateUI() {
            bool requireRelinkEdges = false;
            if (handleKeeper.isDirty) {
                SetTitle();
                var inspector = showInspectorService;
                if (inspector.IsSourceEqual(dataSource)) {
                    inspector.ShowInspector(dataSource, OnInspectorChange, InspectorPane.ShowInspectorType.Refresh);
                }

                // 需要更新输入端口
                if (isMultiInputNode) {
                    RebuildMuitiInputPorts();
                    requireRelinkEdges = true;
                }

                handleKeeper.ClearDirty();
            }
            return requireRelinkEdges;
        }

        private void OnInspectorChange() {
            //var isDirtyBefore = handleKeeper.isDirty;
            //handleKeeper.handle.SetSetupData(handleKeeper.handle.data.modelProperty);
            //if (!isDirtyBefore) {
            //    handleKeeper.ClearDirty();
            //}
        }

        public override void BuildContextualMenu(ContextualMenuPopulateEvent evt) {
            if (ageEnv.ageMode == AGEMode.Edit) {
                base.BuildContextualMenu(evt);
            }
        }
    }

    [NodeMenuItem(typeof(AGANode_Result), null)]
    internal class NodeView_Result : NodeViewBase {
        public override string titleText => "Result";
        protected override NodeViewInspectorSourceBase dataSource => null;

        public NodeView_Result() {
            capabilities &= ~Capabilities.Deletable; //不可删除
        }

        internal override void Init(AGAHandle_Node handle, AnimGraphView graphView, AGEEnvironment ageContext) {
            base.Init(handle, graphView, ageContext);
        }
    }


}